package cn.kz.hrm.service.impl;

import cn.kz.hrm.commonfeiclient.CommonFeignClient;
import cn.kz.hrm.config.RabbitmqConfig;
import cn.kz.hrm.doc.CourseDoc;
import cn.kz.hrm.domain.Course;
import cn.kz.hrm.domain.CourseDetail;
import cn.kz.hrm.domain.CourseMarket;
import cn.kz.hrm.dto.CourseDto;
import cn.kz.hrm.mapper.CourseDetailMapper;
import cn.kz.hrm.mapper.CourseMapper;
import cn.kz.hrm.mapper.CourseMarketMapper;
import cn.kz.hrm.query.CourseQuery;
import cn.kz.hrm.service.ICourseService;
import cn.kz.hrm.util.AjaxResult;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kz
 * @since 2020-06-29
 */
@Service
@Transactional //开启事务，要么都添加成功，要么都添加失败！！
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    private Logger log = LoggerFactory.getLogger(CourseServiceImpl.class);


    @Autowired
    private CourseDetailMapper courseDetailMapper;

    @Autowired
    private CourseMarketMapper courseMarketMapper;

    @Autowired
    private CommonFeignClient commonFeignClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 存储数据。一个表格中的数据当成三份表进行存储，
     * 其中三张表的数据是一对一的存储，即每一张表的id都是一致，即先存储course表
     * 即，将其返回的id赋值给其他两张表的id。保持一致性。
     * @param courseDto
     */
    @Override
    public void saveOrUpdate(CourseDto courseDto) {

        //@todo 每次添加数据都需要对参数的合理性进行判断，然后将其再做业务逻辑，在此做简单的判断
        Course course = courseDto.getCourse(); //主表信息
        CourseDetail courseDetail = courseDto.getCourseDetail(); //课程详情信息
        CourseMarket courseMarket = courseDto.getCourseMarket(); //课程的营销信息

        //简单的判断
        if(course == null){
            throw new RuntimeException("课程信息不能为空，请你仔细填写！！");
        }
        if(courseDetail == null){
            throw new RuntimeException("课程详情信息不能为空，请你仔细填写！！");
        }
        if(courseMarket == null){
            throw new RuntimeException("课程营销信息不能为空，请你仔细填写！！");
        }

        //存储课程
        course.setStatus(Course.STATUS_OFFLINE);//课程状态为下架
        //存储添加课程的人员，此处没有做登录，所以暂且固定。
        course.setUserId(52L);
        course.setUserName("zhondian");
        course.setTenantId(37L); //租户的id
        course.setTenantName("晴天"); //租户（公司）的名字
        baseMapper.insert(course);

        //存储课程的详情信息
        courseDetail.setId(course.getId());
        courseDetailMapper.insert(courseDetail);

        //存储课程的营销信息
        courseMarket.setId(course.getId());
        courseMarketMapper.insert(courseMarket);
    }

    /**
     * 对课程进行上线，修改他的状态为上线，然后将课程存入到ElasticSearch
     * @param id
     */
    @Override
    public void onLineCourse(Long id) {
        //1、查数据，根据id
        Course course = baseMapper.selectById(id);
        //2、对返回的数据进行判断
        if(course == null || course.getStatus() != Course.STATUS_OFFLINE){//状态必须是处于下线状态才可以上线
            throw new RuntimeException("该课程已经处于上线状态，请勿瞎上传！！");
        }
        //3、修改状态为上线
        course.setStatus(Course.STATUS_ONLINE);
        //4、保存数据到mysql
        baseMapper.updateById(course);
        //5、将数据保存到ElasticSearch

        //要将三张表中数据都加入到CourseDoc对象中，
        CourseDetail courseDetail = courseDetailMapper.selectById(id);
        CourseMarket courseMarket = courseMarketMapper.selectById(id);
        //利用工具类将数据进行添加到CourseDoc对象中，转换成文档对象

        CourseDoc courseDoc = new CourseDoc();
        courseDoc.setId(id);
        //将这两个字段进行一起作为分词查询
        courseDoc.setSearchField(course.getName() + courseDetail.getDescription());
        BeanUtils.copyProperties(course,courseDoc );//转换主表层文档对象
        BeanUtils.copyProperties(courseDetail,courseDoc );//转换主表层文档对象
        BeanUtils.copyProperties(courseMarket,courseDoc );//转换主表层文档对象
        //调用feign的controller进行添加。
        AjaxResult ajaxResult = commonFeignClient.saveElasticReseach(courseDoc);//这里走了降级方法
        if(!ajaxResult.isSuccess()){//进行事务回滚
            log.error("添加到ElasticReseach中失败!!");
            throw new RuntimeException("添加到ElasticReseach中失败");
        }

        //todo 对新上线的课程进行推广发送。短信、邮件、站内信都发送 topic通配符发送。“#”都发送，“*”只会发送一级的数据。
        rabbitTemplate.convertAndSend(RabbitmqConfig.COURSE_EXCHANGE_NAME,"course.#",courseDoc.getName());
    }

    /**
     * 对课程进行下线处理，修改状态，同时从ElasticSearch进行删除，根据id进行删除，因为存储的时候
     * 课程的id和ElasticSearch的id是一致的。
     * @param id
     */
    @Override
    public void offLineCourse(Long id) {
        //1、从数据库中查询到该数据
        Course course = baseMapper.selectById(id);
        //1.2 判断数据是否存在以及状态是否为上线，支队上线的数据进行下线
        if(course == null || course.getStatus() != Course.STATUS_ONLINE) {
            throw new RuntimeException("课程下架失败，请选择是上线状态的课程进行下架，否则砍死你！！");
        }
        //2、修改状态为下线
        course.setStatus(Course.STATUS_OFFLINE);
        //3、进行数据的修改
        baseMapper.updateById(course);
        //4、将ElasticSearch中的数据进行删除。根据id进行删除。调用feign接口
        commonFeignClient.deleteElasticReseach(id);


    }

    /**
     * 查询课程的类表显示，根据courseQuery进行查询
     * @param courseQuery
     * @return
     */
    @Override
    public AjaxResult getQueryCourses(CourseQuery courseQuery) {
       return commonFeignClient.getQueryCourses(courseQuery);
    }

    /**
     * 根据课程的id查询课程的信息
     * @param id
     * @return
     */
    @Override
    public CourseDto getCourseById(Long id) {
        Course course = baseMapper.selectById(id);
        CourseMarket courseMarket = courseMarketMapper.selectById(id);
        CourseDto courseDto = new CourseDto();
        courseDto.setCourse(course);
        courseDto.setCourseMarket(courseMarket);
        return courseDto;
    }
}
